using System.Text.Json;
using FreeRedis;

namespace Beauty.Net.Cache.Core;

/// <summary>
/// Redis缓存服务实现
/// </summary>
public class RedisCacheService : ICacheService
{
    private readonly RedisClient _redisClient;
    private readonly JsonSerializerOptions _jsonOptions;

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="redisClient">Redis客户端</param>
    public RedisCacheService(RedisClient redisClient)
    {
        _redisClient = redisClient;
        _jsonOptions = new JsonSerializerOptions
        {
            PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
            WriteIndented = false,
            AllowTrailingCommas = true,
            ReadCommentHandling = JsonCommentHandling.Skip
        };
    }

    /// <summary>
    /// 获取缓存
    /// </summary>
    /// <typeparam name="T">缓存数据类型</typeparam>
    /// <param name="key">缓存键</param>
    /// <returns>缓存值</returns>
    public T? Get<T>(string key)
    {
        var value = _redisClient.Get(key);
        if (string.IsNullOrEmpty(value))
        {
            return default;
        }
        
        return JsonSerializer.Deserialize<T>(value, _jsonOptions);
    }

    /// <summary>
    /// 异步获取缓存
    /// </summary>
    /// <typeparam name="T">缓存数据类型</typeparam>
    /// <param name="key">缓存键</param>
    /// <returns>缓存值</returns>
    public async Task<T?> GetAsync<T>(string key)
    {
        var value = await _redisClient.GetAsync(key);
        if (string.IsNullOrEmpty(value))
        {
            return default;
        }
        
        return JsonSerializer.Deserialize<T>(value, _jsonOptions);
    }

    /// <summary>
    /// 设置缓存
    /// </summary>
    /// <typeparam name="T">缓存数据类型</typeparam>
    /// <param name="key">缓存键</param>
    /// <param name="value">缓存值</param>
    /// <param name="expiry">过期时间</param>
    public void Set<T>(string key, T value, TimeSpan? expiry = null)
    {
        var jsonValue = JsonSerializer.Serialize(value, _jsonOptions);
        if (expiry.HasValue)
        {
            _redisClient.Set(key, jsonValue, (int)expiry.Value.TotalSeconds);
        }
        else
        {
            _redisClient.Set(key, jsonValue);
        }
    }

    /// <summary>
    /// 异步设置缓存
    /// </summary>
    /// <typeparam name="T">缓存数据类型</typeparam>
    /// <param name="key">缓存键</param>
    /// <param name="value">缓存值</param>
    /// <param name="expiry">过期时间</param>
    public async Task SetAsync<T>(string key, T value, TimeSpan? expiry = null)
    {
        var jsonValue = JsonSerializer.Serialize(value, _jsonOptions);
        if (expiry.HasValue)
        {
            await _redisClient.SetAsync(key, jsonValue, (int)expiry.Value.TotalSeconds);
        }
        else
        {
            await _redisClient.SetAsync(key, jsonValue);
        }
    }

    /// <summary>
    /// 删除缓存
    /// </summary>
    /// <param name="key">缓存键</param>
    public void Remove(string key)
    {
        _redisClient.Del(key);
    }

    /// <summary>
    /// 异步删除缓存
    /// </summary>
    /// <param name="key">缓存键</param>
    public async Task RemoveAsync(string key)
    {
        await _redisClient.DelAsync(key);
    }

    /// <summary>
    /// 批量删除缓存
    /// </summary>
    /// <param name="keys">缓存键集合</param>
    public void RemoveRange(IEnumerable<string> keys)
    {
        if (keys.Any())
        {
            _redisClient.Del(keys.ToArray());
        }
    }

    /// <summary>
    /// 异步批量删除缓存
    /// </summary>
    /// <param name="keys">缓存键集合</param>
    public async Task RemoveRangeAsync(IEnumerable<string> keys)
    {
        if (keys.Any())
        {
            await _redisClient.DelAsync(keys.ToArray());
        }
    }

    /// <summary>
    /// 判断缓存是否存在
    /// </summary>
    /// <param name="key">缓存键</param>
    /// <returns>是否存在</returns>
    public bool Exists(string key)
    {
        var result = _redisClient.Exists(key);
        return result is bool boolResult ? boolResult : Convert.ToInt32(result) > 0;
    }

    /// <summary>
    /// 异步判断缓存是否存在
    /// </summary>
    /// <param name="key">缓存键</param>
    /// <returns>是否存在</returns>
    public async Task<bool> ExistsAsync(string key)
    {
        var result = await _redisClient.ExistsAsync(key);
        return result is bool boolResult ? boolResult : Convert.ToInt32(result) > 0;
    }

    /// <summary>
    /// 获取缓存并设置缓存（如果不存在）
    /// </summary>
    /// <typeparam name="T">缓存数据类型</typeparam>
    /// <param name="key">缓存键</param>
    /// <param name="factory">缓存值工厂</param>
    /// <param name="expiry">过期时间</param>
    /// <returns>缓存值</returns>
    public T GetOrSet<T>(string key, Func<T> factory, TimeSpan? expiry = null)
    {
        var value = Get<T>(key);
        if (value is null || (value is string && string.IsNullOrEmpty(value.ToString())))
        {
            value = factory();
            Set(key, value, expiry);
        }
        return value;
    }

    /// <summary>
    /// 异步获取缓存并设置缓存（如果不存在）
    /// </summary>
    /// <typeparam name="T">缓存数据类型</typeparam>
    /// <param name="key">缓存键</param>
    /// <param name="factory">缓存值工厂</param>
    /// <param name="expiry">过期时间</param>
    /// <returns>缓存值</returns>
    public async Task<T> GetOrSetAsync<T>(string key, Func<Task<T>> factory, TimeSpan? expiry = null)
    {
        var value = await GetAsync<T>(key);
        if (value is null || (value is string && string.IsNullOrEmpty(value.ToString())))
        {
            value = await factory();
            await SetAsync(key, value, expiry);
        }
        return value;
    }
}